/*
 * $Id: AbstractTreeTableModel.java 3780 2010-09-09 16:17:41Z kschaefe $
 *
 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package org.jdesktop.swingx.treetable;

import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreePath;

import org.jdesktop.swingx.tree.TreeModelSupport;

// There is no javax.swing.tree.AbstractTreeModel; There ought to be one.

/**
 * AbstractTreeTableModel provides an implementation of
 * {@link org.jdesktop.swingx.treetable.TreeTableModel} as a convenient starting
 * point in defining custom data models for
 * {@link org.jdesktop.swingx.JXTreeTable}. It takes care of listener management
 * and contains convenience methods for creating and dispatching
 * {@code TreeModelEvent}s. To create a concreate instance of
 * {@code TreeTableModel} you need only to provide implementations for the
 * following methods:
 * 
 * <pre>
 * public int getColumnCount();
 * 
 * public Object getValueAt(Object node, int column);
 * 
 * public Object getChild(Object parent, int index);
 * 
 * public int getChildCount(Object parent);
 * 
 * public int getIndexOfChild(Object parent, Object child);
 * 
 * public boolean isLeaf(Object node);
 * </pre>
 * 
 * @author Ramesh Gupta
 * @author Karl Schaefer
 */
public abstract class AbstractTreeTableModel implements TreeTableModel {

	/**
	 * Root node of the model
	 */
	protected Object root;

	/**
	 * Provides support for event dispatching.
	 */
	protected TreeModelSupport modelSupport;

	/**
	 * Constructs an {@code AbstractTreeTableModel} with a {@code null} root
	 * node.
	 */
	public AbstractTreeTableModel() {
		this(null);
	}

	/**
	 * Constructs an {@code AbstractTreeTableModel} with the specified root
	 * node.
	 * 
	 * @param root
	 *            root node
	 */
	public AbstractTreeTableModel(Object root) {
		this.root = root;
		this.modelSupport = new TreeModelSupport(this);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Class<?> getColumnClass(int column) {
		return Object.class;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getColumnName(int column) {
		// Copied from AbstractTableModel.
		// Should use same defaults when possible.
		String result = "";

		for (; column >= 0; column = column / 26 - 1) {
			result = (char) ((char) (column % 26) + 'A') + result;
		}

		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getHierarchicalColumn() {
		if (getColumnCount() == 0) {
			return -1;
		}

		return 0;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Object getRoot() {
		return root;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isCellEditable(Object node, int column) {
		// RG: Fix Issue 49 -- Cell not editable, by default.
		// Subclasses might override this to return true.
		return false;
	}

	/**
	 * Returns <code>true</code> if <code>node</code> is a leaf.
	 *
	 * @impl {@code true} if {@code getChildCount(node) == 0}
	 * @param node
	 *            a node in the tree, obtained from this data source
	 * @return true if <code>node</code> is a leaf
	 */
	@Override
	public boolean isLeaf(Object node) {
		return getChildCount(node) == 0;
	}

	/**
	 * Sets the value for the {@code node} at {@code columnIndex} to
	 * {@code value}.
	 * 
	 * @impl is no-op; provided for convenience for uneditable models
	 * @param value
	 *            the new value
	 * @param node
	 *            the node whose value is to be changed
	 * @param column
	 *            the column whose value is to be changed
	 * @see #getValueAt
	 * @see #isCellEditable
	 * @see javax.swing.table.TableModel#setValueAt(Object, int, int)
	 */
	@Override
	public void setValueAt(Object value, Object node, int column) {
		// does nothing
	}

	/**
	 * Called when value for the item identified by path has been changed. If
	 * newValue signifies a truly new value the model should post a
	 * {@code treeNodesChanged} event.
	 * <p>
	 * 
	 * @impl is no-op. A {@code JXTreeTable} does not usually edit the node
	 *       directly.
	 * @param path
	 *            path to the node that has changed
	 * @param newValue
	 *            the new value from the <code>TreeCellEditor</code>
	 */
	@Override
	public void valueForPathChanged(TreePath path, Object newValue) {
		// does nothing
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void addTreeModelListener(TreeModelListener l) {
		modelSupport.addTreeModelListener(l);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeTreeModelListener(TreeModelListener l) {
		modelSupport.removeTreeModelListener(l);
	}

	/**
	 * Returns an array of all the <code>TreeModelListener</code>s added to this
	 * JXTreeTable with addTreeModelListener().
	 *
	 * @return all of the <code>TreeModelListener</code>s added or an empty
	 *         array if no listeners have been added
	 */
	public TreeModelListener[] getTreeModelListeners() {
		return modelSupport.getTreeModelListeners();
	}
}
